import SerialPort from 'serialport'
import { Context } from 'koa';
const cp = require('child_process').execFile
import { logger } from "../until/log"
import websocketIo from "../until/websocket.io";
import eventEmit from "../until/emitEvent";
import AdminService from '../service/admin.service'
import path from 'path';
import config from '../../config'
import { spawn, Thread, Worker } from 'threads';
import Tool from "../until/tool";

interface IData {
  ID: number;
  data: number[];
  sta: number[];
}


class SocketController {
    public serialName;
    static serialport:SerialPort;
    public baudRate!:number; // 波特率
    static localData:any;
    static isOpenSerial:boolean = false; // 是否打开了串口
    static receiveTime = new Date().getTime(); // 获取接收的时间戳
    static timer:any;
    public thead:any;
    // 批量缓冲与定时刷新，避免高并发写入导致阻塞/崩溃（仅存储数据，不存储状态）
    static dataBuffer: any[] = [];
    static flushTimer: any = null;
    static isFlushing: boolean = false;
    static FLUSH_INTERVAL_MS: number = 3000; // 每3秒批量写入
    static MAX_BATCH_SIZE: number = 200;    // 缓冲达到该阈值则立即写入
    static processHandlersInstalled: boolean = false; // 进程退出钩子是否已安装

    static setupProcessHandlers() {
        if (SocketController.processHandlersInstalled) return;
        SocketController.processHandlersInstalled = true;
        const shutdown = async (signal?: string) => {
            try {
                await SocketController.flushBuffers();
            } catch (e) {
                logger.error("退出前批量写入失败：" + e);
            } finally {
                if (SocketController.flushTimer) {
                    clearInterval(SocketController.flushTimer);
                    SocketController.flushTimer = null;
                }
                if (signal) logger.info(`收到 ${signal}, 已尝试刷新缓冲并清理定时器`);
            }
        }
        process.on('SIGINT', () => shutdown('SIGINT').then(() => process.exit(0)))
        process.on('SIGTERM', () => shutdown('SIGTERM').then(() => process.exit(0)))
        process.on('beforeExit', () => shutdown('beforeExit'))
    }

    static async flushBuffers() {
        if (SocketController.isFlushing) return;
        const hasData = SocketController.dataBuffer.length > 0;
        if (!hasData) return;
        SocketController.isFlushing = true;
        try {
            // 先拷贝再写库，成功后按拷贝长度清理，避免失败时数据丢失
            const snapshot = SocketController.dataBuffer.slice();
            if (snapshot.length) {
                await AdminService.saveBulkData(snapshot);
                // 清理已经成功写入的这部分，保留写库期间新增的数据
                SocketController.dataBuffer.splice(0, snapshot.length);
                logger.info(`已经批量存储了${snapshot.length}条数据`)
            }
        } catch (err) {
            logger.error("批量写入失败：" + err);
        } finally {
            SocketController.isFlushing = false;
        }
    }
    //重写报警逻辑
    public catchError(data: IData):IData {
        let catch_uv = eventEmit.settingData[data.ID - 1][0].current_val // 紫外报警阈值
        let catch_ir = eventEmit.settingData[data.ID - 1][1].current_val // 红外报警阈值
        let catch_temp = eventEmit.settingData[data.ID - 1][2].current_val // 温度报警阈值
        let catch_hum = eventEmit.settingData[data.ID - 1][3].current_val // 湿度报警阈值
        let catch_pre = eventEmit.settingData[data.ID - 1][4].current_val // 压力报警阈值
        let catch_param = [catch_uv, catch_ir, catch_temp, catch_hum, catch_pre]
        let new_sta: number[] = data.data.map((item: any,index: number) => {
            if (item > catch_param[index]) {
                return 1
            } else {
                return 0
            }
        } )
        return {
            ID: data.ID,
            data: data.data,
            sta: new_sta
        }
    }
    // 连接串口
    async connectionSerialport(serialName,baudRate:number,parity) {
        this.baudRate = baudRate
        this.serialName = serialName
        // @ts-ignore
        SocketController.serialport = new SerialPort(this.serialName,{baudRate: this.baudRate,dataBits:8,parity},(err) => {
            if (err) return console.log("打开串口失败" + err)
                    console.log(`打开${this.serialName}串口成功!!!`)
                     eventEmit.emit('polling_call',SocketController.serialport)
                     SocketController.isOpenSerial = true
                    // 启动批量写入定时器
                    if (!SocketController.flushTimer) {
                        SocketController.flushTimer = setInterval(() => {
                              if (SocketController.dataBuffer.length >= SocketController.MAX_BATCH_SIZE) {
                                SocketController.flushBuffers()
                            }
                        }, SocketController.FLUSH_INTERVAL_MS)
                        // 安装进程退出钩子，确保退出前尽可能刷新缓冲
                        SocketController.setupProcessHandlers()
                    }
                    try {
                        // 把数据传递给前端
                        SocketController.serialport.on('data',async (res) => {
                            let baseInfo:Array<number> = res.toJSON().data
                            console.log(res)
                            // 加上帧头和针尾的校验
                            if (baseInfo.length === 20 && baseInfo[0] === 247 && baseInfo[1] === 247 && baseInfo[18] === 127 && baseInfo[19] === 127) {
                                let module_id = baseInfo[2]
                                let tem = ((baseInfo[5] *256 + baseInfo[6])/100).toFixed(1)
                                let hum = ((baseInfo[7] *256 + baseInfo[8])/100).toFixed(1)
                                let pre = ((baseInfo[9] *256 + baseInfo[10])/100).toFixed(1)
                                let inf = ((baseInfo[11] *256 + baseInfo[12])/100).toFixed(1)
                                let uv = (baseInfo[13] * 256 + baseInfo[14])
                                uv = uv > 32767? 65535 - uv : uv
                                let data = {
                                    ID: module_id,
                                    data: [uv,Number(inf), Number(tem),Number(hum), Number(pre)],
                                    sta: [0,0,0,0,0]
                                }
                            data = this.catchError(data) // 重写报警逻辑     
                            logger.info(JSON.stringify(data))
                            // 改为批量写入：入缓冲，定时/超阈值触发批量落库
                            SocketController.dataBuffer.push({
                                module_id: data.ID,
                                uvc: data.data[0],
                                inf: data.data[1],
                                tem: data.data[2],
                                hum: data.data[3],
                                pre: data.data[4],
                                time: new Date().toLocaleTimeString(),
                                date: Tool.getCurrentDate()
                            })
                          
                            if (websocketIo.getInstance.socketObj) websocketIo.getInstance.socketObj.send(JSON.stringify({...data,action: 'sendData'}))
                            }
                           
                    })
                    } catch (err) {
                        logger.error("传输的数据格式有问题：" + err)
                    }
        })
    }
    static isSend() {
     return new Promise((resolve => {
         let sendTime = new Date().getTime()  // 获取发送的时间
         let spaceTime = sendTime - SocketController.receiveTime // 获取发送和接收的时间间隔
         if (spaceTime > 200 && spaceTime < 800) {
              resolve(true)
         } else {
             console.log("相撞了")
              resolve(false)
         }
     }))
    }
    // 获取串口数据
    getSerialPort(ctx:Context){
        if (SocketController.isOpenSerial) {
            ctx.body = {
                code: 200,
                msg: "获取串口数据成功",
                data: SocketController.localData
               }
        } else {
            ctx.body = {
                code: 304,
                msg: "还没有打开串口"
            }
        }
    }
    async changeSerialPort(ctx:any) {
        let varNameList = ['uv','inf',"acc",'tem','hum','pre'] // 定义一个变量的数组
        let id = ctx.request.body.id
        let device_id = ctx.request.body.device_id // 设备的id
        let alarm = ctx.request.body.currentValue
         let obj = {
             ID: device_id,
             [varNameList[id - 1]]: {alarm:[alarm]}
         }
        try {
           let bool = await SocketController.isSend()
            if (bool) {
                let bool = await SocketController.serialport.write(JSON.stringify(obj).trim())
            } else {
                setTimeout(() => {
                    SocketController.serialport.write(JSON.stringify(obj).trim(),(err) => {
                        if (err) return console.log("写入失败")
                    })
                },200)
            }
        } catch(err) {
            logger.error("修改阈值失败" + err)
            ctx.body = {code: 500,msg:"修改阈值失败，查看设备连接"}
        }
            ctx.body = {
                code: 200,
                msg: "修改成功",
                data: obj
            }
    }
    async changeSpeed(ctx:any) {
        // 改变数据采样的速率
        let bool = await SocketController.isSend()
        let speed = ctx.request.body.speed
        if (bool) {
            await SocketController.serialport.write(`{DELAY:[${speed}]}`,(err) => {
                if (err) return ctx.body = {code: 500,msg: "修改失败"}
            })
            ctx.body = {code: 200,msg: "修改速率成功"}
        } else {
            setTimeout(() => {
                SocketController.serialport.write(`{DELAY:[${speed}]}`,(err) => {
                    if (err) return ctx.body = {code: 500,msg: "修改失败"}
                })
            },200)
            ctx.body = { code: 200,msg: "修改速率成功" }
        }
    }
    // 获取模块的个数
    async getModuleNum(ctx:Context) {
        ctx.body = {
            code: 200,
            msg: "获取模块的个数成功",
            data: {
                moduleNum: eventEmit.moduleNum,
                uv: config.uv,
                inf: config.inf,
                other: config.other
            }
        }
    }
}

export default new SocketController
